/**
 * IBM Confidential
 * 
 * OCO Source Materials
 * 
 * 5724-R76
 * 
 * © Copyright IBM Corp. 2001, 2009
 * 
 * The source code for this program is not published or otherwise
 * divested of its trade secrets, irrespective of what has
 * been deposited with the U.S. Copyright Office.
 */
package com.ibm.ecm.configmgr.app.acm.widgets.util;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.BufferedWriter;
import java.io.InputStream;
import java.io.StringReader;
import java.io.OutputStreamWriter;
import java.io.FileOutputStream;

import java.io.Writer;
import java.util.Iterator;

import javax.xml.namespace.NamespaceContext;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathException;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;

import org.apache.xml.serialize.OutputFormat;
import org.apache.xml.serialize.XMLSerializer;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
import org.w3c.dom.NodeList;
import org.xml.sax.EntityResolver;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;

public class XMLUtils {
	private Document doc = null;
	private String filename = null;

	public XMLUtils(String configureFile) throws Exception {

		File file = new File(configureFile);
		init(file);

	}
	public XMLUtils(File file) throws Exception {

		init(file);

	}
	public XMLUtils(InputStream in) throws Exception {

		init(in);

	}
	public XMLUtils(String parentFolder, String fileName) throws Exception  {
		
		File file = new File(parentFolder, fileName);
		init(file);
	
	}
	
	private void init(File file) throws ParserConfigurationException,
			SAXException, IOException {
		
		if (!file.exists()) {
			System.out.println(file.getPath() + " does not exist!");
			throw new FileNotFoundException(file.getPath() + " does not exist!");
		}
		this.filename = file.getPath();
		
		DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
		factory.setNamespaceAware(true);
		DocumentBuilder builder;
		try {
			builder = factory.newDocumentBuilder();
			builder.setEntityResolver(new EntityResolver(){
				public InputSource resolveEntity(String arg0, String arg1) 
				throws SAXException, IOException {
			    // TODO Auto-generated method stub
			    return new InputSource(new StringReader(""));
		        }
			});
			doc = builder.parse(file);
			doc.normalize();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
			throw e;
		}
	}

	private void init(InputStream in) throws ParserConfigurationException,
	SAXException, IOException {

DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
factory.setNamespaceAware(true);
DocumentBuilder builder;
try {
	builder = factory.newDocumentBuilder();
	builder.setEntityResolver(new EntityResolver(){
		public InputSource resolveEntity(String arg0, String arg1) 
		throws SAXException, IOException {
	    // TODO Auto-generated method stub
	    return new InputSource(new StringReader(""));
        }
	});
	doc = builder.parse(in);
	doc.normalize();
} catch (IOException e) {
	// TODO Auto-generated catch block
	e.printStackTrace();
	throw e;
}
}

	public String getNodeData(String xPath) throws XPathException {

		Node node = getNode(xPath);

		return node.getFirstChild().getNodeValue();
	}

	public void updateNode(String path, String data) throws XPathException {

		Node node = getNode(path);
		if (node != null) {
			node.getFirstChild().setNodeValue(data);
			save();
		} else {
			System.out.println("Node: " + path + "  is not updated.");
		}

	}

	public void updateDocument(String path, String data) throws XPathException {

		Node node = getNode(path);
		if (node != null) {
			node.getFirstChild().setNodeValue(data);
		} else {
			System.out.println("Node: " + path + "  is not updated.");
		}

	}
	public void appendNode(String parentPath, Node node) throws XPathException {

		// XPathFactory xPathFactory = XPathFactory.newInstance();
		// XPath xpath = xPathFactory.newXPath();
		//
		// XPathExpression expr = xpath.compile(parentPath);
		// NodeList nodes = ((NodeList) expr.evaluate(doc,
		// XPathConstants.NODESET));
		Node parentNode = getNode(parentPath);
		if (node != null) {
			Element parent = (Element) parentNode;
			parent.appendChild(node);
			save();
		} else {
			System.out.println("Parent Node: " + parentPath
					+ "  is not found. No child is appended");
		}

	}

	public void insertNode(String parentPath, String before, Node node)
			throws XPathException {

		// XPathFactory xPathFactory = XPathFactory.newInstance();
		// XPath xpath = xPathFactory.newXPath();
		//
		// XPathExpression expr = xpath.compile(parentPath);
		// NodeList nodes = ((NodeList) expr.evaluate(doc,
		// XPathConstants.NODESET));
		Node parentNode = getNode(parentPath);
		Node beforeNode = getNode(before);
		if (parentNode != null && beforeNode != null) {
			Element parent = (Element) parentNode;
			parent.insertBefore(node, beforeNode);
			save();
		} else {
			System.out.println("Parent Node: " + parentPath
					+ "  or previous node: " + before
					+ " is not found. No child is appended");
		}
	}

	/**
	 * Save XML configuration file
	 */
	private void save() {

		OutputFormat format = new OutputFormat(doc);
		format.setIndenting(true);
		format.setIndent(4);
		format.setEncoding("UTF-8");
		try {
			//BufferedWriter output = new BufferedWriter(new FileWriter(filename));
			Writer output = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(filename),"UTF-8"));
			XMLSerializer serializer = new XMLSerializer(output, format);
			serializer.serialize(doc);
		} catch (IOException e) {
			e.printStackTrace();
			throw new RuntimeException(e);
		}
	}

	private XPathExpression getXPathExpression(String path)
			throws XPathException {
		XPathFactory xPathFactory = XPathFactory.newInstance();

		XPath xpath = xPathFactory.newXPath();
		xpath.setNamespaceContext(new NamespaceContext() {
			public String getNamespaceURI(String prefix) {
				if (prefix.equals("catalog")) {
					return "http://www.ibm.com/xmlns/atom/opensearch/iwidget/1.0/";
				} else if (prefix.equals("atom")) {
					return "http://www.w3.org/2005/Atom";
				} else if (prefix.equals("base")) {
					return "http://www.ibm.com/xmlns/prod/lotus/mashups/v1.0/base";
				}else if (prefix.equals("ext")) {
					return "http://www.ibm.com/xmlns/prod/lotus/mashups/v1.0/extensions";
				}
				else if (prefix.equals("model")){
					return "http://www.ibm.com/xmlns/prod/lotus/mashups/v1.0/model-elements";
				}
				else if (prefix.equals("xml")){
					return "http://www.ibm.com/xmlns/prod/lotus/mashups/v1.0/xml";
				}
		        else{
			       return "http://www.ibm.com/xmlns/prod/lotus/mashups/v1.0/";
		        }
			}

			public String getPrefix(String namespaceURI) {
				return null;
			}

			public Iterator getPrefixes(String namespaceURI) {
				return null;
			}
		});

		return xpath.compile(path);
	}

	public Node getNode(String path) throws XPathException {

		// Get node
		NodeList nodes = (NodeList) getXPathExpression(path).evaluate(doc,
				XPathConstants.NODESET);
		if (nodes.getLength() > 0) {
			// return nodes.item(0).getFirstChild();
			return nodes.item(0);
		} else {
			return null;
		}
	}
	
	/**
     * Get value of the node. The method will return  the "first child  node"
     * of this node.
     */
    public String getNodeValue(String nodeName) throws Exception
    {
        String value=null;
        NodeList child = doc.getElementsByTagName(nodeName);
        if (child != null) {
        	value = child.item(0).getChildNodes().item(0).getNodeValue();
        }
        
       return value;
    }
    

	public NodeList getNodes(String path) throws XPathException {

		// Get node
		NodeList nodes = (NodeList) getXPathExpression(path).evaluate(doc,
				XPathConstants.NODESET);
		if (nodes.getLength() > 0) {
			// return nodes.item(0).getFirstChild();
			return nodes;
		} else {
			return null;
		}
	}

	public Document getDocument() {
		return this.doc;
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) throws Exception {
		// TODO Auto-generated method stub
		XMLUtils util = new XMLUtils("C:/ecmwidgetsWidgets.xml");
		util.updateNode("//tns:Widget/tns:helpUrl[../tns:id=\"com.ibm.im.ecmwidgets.iwidget.Toolbar\"]", "http://cmfogbert.usca.ibm.com:8080/ewdoc450/ecmwidgets_help/ref/toolbar_widget.htm");
	}

}
